//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2006
//
// Add point to polygon/polyline.
//

# include "StdAfx.h"
# include "AddPoint.h"
# include "UndoRedo.h"
# include "Label.h"
# include "MapView.h"

class CAddPointAction : public CEditAction {
  public:
	CAddPointAction (rgn_t * _pRgn, size_t _cElement, size_t _cPointIndex, const point_t & _pointNew) :
		m_pRgn (_pRgn),
		m_cElement (_cElement),
		m_cPointIndex (_cPointIndex),
        m_pointNew(_pointNew),
		m_bWasModified ((_pRgn->dwFlags & rgn_t::fModified) != 0)
	{}

	virtual void GetName (string_t & _str) const;
	virtual cu_t CanUndo () const {return cuYes;}
	virtual bool Do ();
	virtual void Undo ();
	virtual void Redo ();

  private:
	rgn_t * const m_pRgn;
	size_t  const m_cElement;
	size_t  const m_cPointIndex;
    point_t const m_pointNew;
	bool    const m_bWasModified;
};

void CAddPointAction::GetName (string_t & _str) const {
	_str.append ("add point [");
	GetHintText (* m_pRgn, _str);
	_str.append ("]");
}

bool CAddPointAction::Do () {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);
	assert (m_cElement < m_pRgn->elements.size ());
	rgn_element_t & element = m_pRgn->elements [m_cElement];

	points_t & points = element.points;
	const size_t cPrevSize = points.size ();
	points.insert (points.begin () + m_cPointIndex + 1, m_pointNew);

	if (element.pExtra != NULL) {
		point_extras_t & PointExtras = element.pExtra->PointExtras;
		if (! PointExtras.empty ()) {
			PointExtras.resize (cPrevSize);
			PointExtras.insert (PointExtras.begin () + m_cPointIndex + 1, point_extra_t ());
			assert (PointExtras.size () == points.size ());
		}
	}

	m_pRgn->RefreshAttributes (g_map);
	m_pRgn->dwFlags |= rgn_t::fModified;

	return true;
}

void CAddPointAction::Undo () {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);
	assert (m_cElement < m_pRgn->elements.size ());
	rgn_element_t & element = m_pRgn->elements [m_cElement];

	points_t & points = element.points;
	const size_t cPrevSize = points.size ();
	points.erase (points.begin () + m_cPointIndex + 1);

	if (element.pExtra != NULL) {
		point_extras_t & PointExtras = element.pExtra->PointExtras;
		if (! PointExtras.empty ()) {
			PointExtras.resize (cPrevSize);
			PointExtras.erase (PointExtras.begin () + m_cPointIndex + 1);
			assert (PointExtras.size () == points.size ());
		}
	}

	m_pRgn->RefreshAttributes (g_map);
	if (! m_bWasModified)
		m_pRgn->dwFlags &= ~rgn_t::fModified;
}

void CAddPointAction::Redo () {
	CAddPointAction::Do ();
}

void AddPoint (rgn_t * _pRgn, size_t _cElement, size_t _cPointIndex, const point_t & _pointNew) {
	assert (_pRgn);
	assert (_pRgn->IsPolyline () || _pRgn->IsPolygon ());
	assert (_cPointIndex < _pRgn->elements [_cElement].points.size ());

	PerformEditAction (new CAddPointAction (_pRgn, _cElement, _cPointIndex, _pointNew));

	Refresh ();
}
